package com.ziytek.web.citizen.job;

import com.ziytek.web.citizen.caffeine.CachePutOrGet;
import com.ziytek.web.citizen.config.caffeine.CaffeineUtil;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.mapper.BasicCabinetIpMapper;
import com.ziytek.web.citizen.mapper.BoardConfigMapper;
import com.ziytek.web.citizen.model.bean.SqliteSwitchVo;
import com.ziytek.web.citizen.model.vo.OperationVo;
import com.ziytek.web.citizen.pojo.basic.DoorConfig;
import com.ziytek.web.citizen.service.DoorsService;
import com.ziytek.web.citizen.service.OperationVoCacheService;
import com.ziytek.web.citizen.service.itf.CabinetNoService;
import com.ziytek.web.citizen.service.itf.SqliteSwitchService;
import com.ziytek.web.citizen.util.KeyUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * sqlite数据库切换任务管理类
 *
 * @author fengh
 */

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SqliteSwitchJob {
    private final DoorsService doorsService;
    private final CachePutOrGet cachePutOrGet;
    private final CabinetNoService cabinetNoService;
    private final BoardConfigMapper boardConfigMapper;
    private final BasicCabinetIpMapper cabinetIpMapper;
    private final SqliteSwitchService sqliteSwitchService;
    private final OperationVoCacheService operationVoCacheService;

    /***
     * 每天凌晨0点执行一次sqlite数据库切换任务
     * */
    @Scheduled(cron = "30 0 0 * * ?")
    public void sqliteSwitch() {
        switched(NumConstant.INT_ZERO);
    }

    public void switched(int times) {
        log.info("sqlite数据库切换任务开始执行");

        //sqlite数据库切换任务代码
        // 1. 先判断是否有interceptor_insert缓存，如果有，则不执行sqlite数据库切换任务
        // 2. 再判断是否有command_operate_all缓存，如果有，则不执行sqlite数据库切换任务
        // 3. 如果没有interceptor_insert缓存，则判断是否有单个操作缓存，如果有，则不执行sqlite数据库切换任务
        Boolean hasInterceptorInsert = CaffeineUtil.get(CaffeineUtil.INTERCEPTOR_INSERT);
        var hasInterceptor = hasInterceptorInsert != null && hasInterceptorInsert;

        var timeCount = cachePutOrGet.getOperateAllCache();
        var allOperationCache = timeCount != null && timeCount > NumConstant.INT_ZERO;
        var hasSingleOperation = false;
        if (!allOperationCache) {
            hasSingleOperation = singleHasOperation();
        }
        var canNotSwitch = hasInterceptor && (allOperationCache || hasSingleOperation);
        if (canNotSwitch) {
            log.info("command_operate_all缓存存在，不执行sqlite数据库切换任务,hasSingleOperation:{},allOperationCache:{}", hasSingleOperation, allOperationCache);
            // todo 放入延时缓存，等待缓存过期后再执行
            var vo = new SqliteSwitchVo();
            vo.setTimes(times + NumConstant.INT_ONE);
            vo.setTimeStamp(System.currentTimeMillis());
            if (vo.getTimes() <= NumConstant.INT_TEN) {
                CaffeineUtil.set(CaffeineUtil.SQLITE_SWITCH_CACHE_PREFIX, vo, vo.getTimes() * 10);
            }
            return;
        }

        sqliteSwitchService.switchDb();

        log.info("sqlite数据库切换任务执行完毕");
    }

    private boolean singleHasOperation() {
        List<DoorConfig> doors = doorsService.getDoorsConfig();
        if (CollectionUtils.isEmpty(doors)) {
            log.info("doors is null");
            return false;
        }

        List<String> ipQueryList = cabinetNoService.getStringList();
        if (CollectionUtils.isEmpty(ipQueryList)) {
            log.info("ipQueryList is null");
            return false;
        }

        var cabinetNoList = cabinetIpMapper.queryCabinetNoByIp(ipQueryList);
        if (CollectionUtils.isEmpty(cabinetNoList)) {
            log.info("cabinetNoLists is null");
            return false;
        }


        List<Integer> channelList = new ArrayList<>();
        channelList.add(NumConstant.INT_ONE);
        channelList.add(NumConstant.INT_TWO);
        channelList.add(NumConstant.INT_THREE);
        channelList.add(NumConstant.INT_FOUR);
        channelList.add(NumConstant.INT_FIVE);
        channelList.add(NumConstant.INT_SIX);
        channelList.add(NumConstant.INT_SEVEN);
        channelList.add(NumConstant.INT_EIGHT);


        for (var cn : cabinetNoList) {
            for (var door : doors) {
                var boardAddress = boardConfigMapper.queryByDoorListNum(door.getDoor());
                for (var address : boardAddress) {
                    for (var cnn : channelList) {
                        var k = KeyUtil.commandOperateKey(cn.getCabinetNo(), address, cnn);
                        OperationVo vo =  operationVoCacheService.getOperationVo(k);
                        if (vo != null && vo.getStartFlag() != NumConstant.INT_ONE) {
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }
}
